import React, { useEffect, useRef, useCallback } from 'react';
import { Graph, Shape, Node, Edge } from '@antv/x6';
import '@antv/x6-react-shape';
import { History } from '@antv/x6-plugin-history';
import { Clipboard } from '@antv/x6-plugin-clipboard';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import { Snapline } from '@antv/x6-plugin-snapline';
import { Selection } from '@antv/x6-plugin-selection';
import { Transform } from '@antv/x6-plugin-transform';
import { DeviceGraphList } from './conf';
import type { CanvasElement } from './types';
import type { ViewportState } from '@/hooks/useViewport';

// 注册自定义节点
Graph.registerNode(
  'custom-element',
  {
    markup: [
      {
        tagName: 'rect',
        selector: 'body',
      },
      {
        tagName: 'image',
        selector: 'icon',
      },
      {
        tagName: 'text',
        selector: 'label',
      },
    ],
    attrs: {
      body: {
        refWidth: '100%',
        refHeight: '100%',
        stroke: '#d9d9d9',
        strokeWidth: 1,
        fill: '#fff',
        rx: 4,
        ry: 4,
      },
      icon: {
        'xlink:href': '',
        width: '100%',
        height: '100%',
      },
      label: {
        text: '',
        fill: '#333',
        fontSize: 12,
      },
    },
  },
  true
);

/**
 * X6画布组件属性
 */
interface X6CanvasProps {
  elements: CanvasElement[];
  edges?: any[];
  onSelectElement: (element: CanvasElement | any | null) => void;
  onUpdateElement: (id: string, properties: any) => void;
  onAddElement: (element: CanvasElement) => void;
  onRemoveElement: (id: string) => void;
  onAddEdge?: (edge: any) => void;
  onRemoveEdge?: (id: string) => void;
  scale: number;
  canvasSize?: { width: number; height: number };
  viewport?: ViewportState;
  readOnly?: boolean;
  gridOptions?: any;
  backgroundOptions?: any;
}

/**
 * X6画布组件
 * 用于渲染和交互组态图元素
 */
const X6Canvas: React.FC<X6CanvasProps> = props => {
  const { elements, edges = [], scale, canvasSize, readOnly = false } = props;
  const containerRef = useRef<HTMLDivElement>(null);
  const graphRef = useRef<Graph | null>(null);
  const selectOnAddRef = useRef<string | null>(null);
  const selectedNodeIdRef = useRef<string | null>(null);
  const selectedEdgeIdRef = useRef<string | null>(null);
  const listenersAddedRef = useRef<boolean>(false);

  const propsRef = useRef(props);
  propsRef.current = props;

  // ==================== 初始化 X6 画布 ====================
  useEffect(() => {
    if (!containerRef.current) return;

    const graph = new Graph({
      container: containerRef.current,
      width: canvasSize?.width || containerRef.current.clientWidth,
      height: canvasSize?.height || containerRef.current.clientHeight,
      grid: props.gridOptions,
      background: props.backgroundOptions,

      translating: { restrict: true },
      interacting: !readOnly,
      connecting: {
        snap: !readOnly,
        allowBlank: !readOnly,
        allowNode: !readOnly,
        allowLoop: false,
        highlight: false,
        validateConnection: () => !readOnly,
        connector: 'normal',
        connectionPoint: 'anchor',
        anchor: 'center',
        router: { name: 'normal' },
        createEdge: () =>
          new Shape.Edge({
            attrs: {
              line: {
                stroke: '#5F95FF',
                strokeWidth: 2,
                targetMarker: { name: 'classic', size: 8 },
              },
            },
            zIndex: 1000,
          }),
      },
      highlighting: {
        magnetAvailable: {
          name: 'stroke',
          args: { attrs: { fill: '#fff', stroke: '#5F95FF', strokeWidth: 2 } },
        },
      },
    });

    graphRef.current = graph;

    const handleDragOver = (e: DragEvent) => e.preventDefault();
    const handleDrop = (e: DragEvent) => {
      e.preventDefault();
      e.stopPropagation();
      if (readOnly) return;
      const deviceType = e.dataTransfer?.getData('deviceType');
      if (!deviceType || !graphRef.current) return;
      const pos = graphRef.current.pageToLocal(e.clientX, e.clientY);

      if (deviceType === 'image') {
        const newId = crypto.randomUUID();
        const newElement: CanvasElement = {
          id: newId,
          type: 'image',
          position: pos,
          size: { width: 200, height: 150 },
          properties: {
            name: `图片-${newId.substring(0, 8)}`,
            imageUrl: '',
            backgroundColor: '#ffffff',
            backgroundEnabled: true,
            borderEnabled: false,
            borderColor: '#d9d9d9',
            borderWidth: 1,
            borderStyle: 'solid',
            labelEnabled: false,
            backgroundFit: 'contain',
            backgroundPosition: 'center',
          },
          angle: 0,
          zIndex: 100,
        };
        selectOnAddRef.current = newElement.id;
        propsRef.current.onAddElement(newElement);
        return;
      }

      if (deviceType === 'text') {
        const newId = crypto.randomUUID();
        const newElement: CanvasElement = {
          id: newId,
          type: 'text',
          position: { x: pos.x, y: pos.y },
          size: { width: 100, height: 30 },
          properties: {
            name: `文本-${newId.substring(0, 8)}`,
            textContent: '文本内容',
            labelEnabled: true,
            labelColor: '#333333',
            labelFontSize: 12,
            labelFontWeight: 'normal',
            labelWrap: 'normal',
            labelVSpan: 0,
            labelHSpan: 0,
            labelPosition: 'center',
            backgroundEnabled: false,
            backgroundColor: '#ffffff',
            borderEnabled: false,
            borderColor: '#d9d9d9',
            borderWidth: 1,
            borderStyle: 'solid',
          },
          angle: 0,
          zIndex: 100,
        };
        selectOnAddRef.current = newElement.id;
        propsRef.current.onAddElement(newElement);
        return;
      }

      if (deviceType === 'connection-line') {
        const newId = crypto.randomUUID();
        const newEdge = {
          id: newId,
          source: { x: pos.x - 50, y: pos.y },
          target: { x: pos.x + 50, y: pos.y },
          router: { name: 'normal' },
          connector: { name: 'normal' },
          attrs: {
            line: {
              stroke: '#5F95FF',
              strokeWidth: 2,
              targetMarker: { name: 'classic', size: 8 },
              style: { cursor: 'pointer' },
            },
          },
          zIndex: 1000,
        };
        propsRef.current.onAddEdge?.(newEdge);
        return;
      }

      const deviceConfig = DeviceGraphList.find(device => device.type === deviceType);
      if (!deviceConfig) return;
      const newId = crypto.randomUUID();
      const newElement: CanvasElement = {
        id: newId,
        type: deviceType,
        position: { x: pos.x, y: pos.y },
        size: { width: deviceConfig.width, height: deviceConfig.height },
        properties: {
          name: `${deviceConfig.name}-${newId.substring(0, 8)}`,
          icon: `device-${deviceConfig.name}`,
        },
        angle: 0,
        zIndex: 100,
      };
      selectOnAddRef.current = newElement.id;
      propsRef.current.onAddElement(newElement);
    };

    if (!readOnly) {
      graph.use(new History({ enabled: true }));
      graph.use(new Clipboard({ enabled: true }));
      graph.use(new Keyboard({ enabled: true, global: true }));
      graph.use(new Snapline({ enabled: true, sharp: true }));
      graph.use(
        new Selection({
          enabled: true,
          multiple: true,
          rubberband: true,
          movable: true,
          showNodeSelectionBox: true,
          showEdgeSelectionBox: true,
        })
      );
      graph.use(
        new Transform({
          resizing: {
            enabled: true,
          },
          rotating: {
            enabled: true,
          },
        })
      );

      graph.on('edge:connected', ({ isNew, edge }) => {
        if (isNew)
          propsRef.current.onAddEdge?.({
            id: edge.id,
            source: edge.getSource(),
            target: edge.getTarget(),
            router: edge.getRouter(),
            connector: edge.getConnector(),
            attrs: edge.getAttrs(),
          });
      });
      graph.on('edge:removed', ({ edge }) => propsRef.current.onRemoveEdge?.(edge.id));
      graph.on('edge:added', ({ edge }) => {
        if (!propsRef.current.edges?.some(e => e.id === edge.id))
          propsRef.current.onAddEdge?.({
            id: edge.id,
            source: edge.getSource(),
            target: edge.getTarget(),
            vertices: edge.getVertices(),
            router: edge.getRouter(),
            connector: edge.getConnector(),
            attrs: edge.getAttrs(),
          });
      });
      const handleEdgeSelect = (edge: any) => {
        if (selectedEdgeIdRef.current === edge.id) return;
        selectedEdgeIdRef.current = edge.id;
        try {
          graph.cleanSelection();
          graph.select(edge);
          const currentStroke = edge.attr('line/stroke') || '#5F95FF';
          const currentStrokeWidth = edge.attr('line/strokeWidth') || 2;
          edge.attr({
            'line/stroke': '#5F95FF',
            'line/strokeWidth': Math.max(currentStrokeWidth + 1, 3),
          });
          // 使用data存储原始样式，避免访问受保护的store属性
          edge.setData({
            ...edge.getData(),
            originalStroke: currentStroke,
            originalStrokeWidth: currentStrokeWidth,
          });
          const edgeData = propsRef.current.edges?.find(e => e.id === edge.id);
          if (edgeData) {
            propsRef.current.onSelectElement({
              ...edgeData,
              source: edge.getSource(),
              target: edge.getTarget(),
              vertices: edge.getVertices(),
              router: edge.getRouter(),
              connector: edge.getConnector(),
              attrs: edge.getAttrs(),
            });
          } else {
            propsRef.current.onSelectElement({
              id: edge.id,
              source: edge.getSource(),
              target: edge.getTarget(),
              vertices: edge.getVertices(),
              router: edge.getRouter(),
              connector: edge.getConnector(),
              attrs: edge.getAttrs(),
            });
          }
        } catch (error) {
          console.error('Error in handleEdgeSelect:', error);
        }
      };
      graph.on('edge:click', ({ edge }) => handleEdgeSelect(edge));
      graph.on('edge:mouseup', ({ edge }) => handleEdgeSelect(edge));
      // 监听选择变化事件
      graph.on('selection:changed', ({ selected }) => {
        // 清除边的选中效果
        graph.getEdges().forEach(edge => {
          edge.removeTools();
          const edgeData = edge.getData();
          const originalStroke = edgeData?.originalStroke;
          const originalStrokeWidth = edgeData?.originalStrokeWidth;
          if (originalStroke || originalStrokeWidth) {
            edge.attr({ 'line/stroke': originalStroke, 'line/strokeWidth': originalStrokeWidth });
            // 清除存储的原始样式数据
            const { originalStroke: _, originalStrokeWidth: __, ...restData } = edgeData || {};
            edge.setData(restData);
          }
        });

        selectedEdgeIdRef.current = null;

        // 只有单选节点时才更新属性面板
        if (selected.length === 1 && selected[0].isNode()) {
          selectedNodeIdRef.current = selected[0].id;
          const element = propsRef.current.elements.find(e => e.id === selected[0].id);
          propsRef.current.onSelectElement(element || null);
        } else {
          // 多选或无选择时清空属性面板
          selectedNodeIdRef.current = null;
          propsRef.current.onSelectElement(null);
        }
      });

      graph.on('cell:click', ({ cell }) => {
        if (cell.isNode()) {
          // 节点点击逻辑由 selection:changed 事件处理
        }
      });
      graph.on('blank:click', () => {
        graph.cleanSelection();
        // 手动移除所有节点和边的工具（hover效果）
        graph.getNodes().forEach(node => {
          const element = propsRef.current.elements.find(e => e.id === node.id);
          if (element?.type !== 'background' && !element?.properties?.locked) {
            node.removeTools();
            const ports = node.getPorts();
            if (ports.length > 0) {
              ports.forEach(port => {
                if (port.id) node.setPortProp(port.id, 'attrs/circle/style/visibility', 'hidden');
              });
            }
          }
        });
        graph.getEdges().forEach(edge => {
          edge.removeTools();
        });
        // 清空选择会触发 selection:changed 事件，自动处理属性面板更新
      });
      graph.on('node:removed', ({ node }) => propsRef.current.onRemoveElement(node.id));
      graph.on('node:moved', ({ node }) => {
        const position = (node as Node).getPosition();
        propsRef.current.onUpdateElement(node.id, { position });
      });
      graph.on('node:resized', ({ node }) => {
        const size = (node as Node).getSize();
        propsRef.current.onUpdateElement(node.id, { size });
      });
      graph.on('node:rotated', ({ node }) => {
        const angle = (node as Node).getAngle();
        propsRef.current.onUpdateElement(node.id, { angle });
      });
      graph.on('node:mouseenter', ({ node }) => {
        const element = propsRef.current.elements.find(e => e.id === node.id);
        if (
          node.id === selectedNodeIdRef.current ||
          element?.type === 'background' ||
          element?.properties?.locked
        )
          return;
        (node as Node).addTools([
          {
            name: 'boundary',
            args: {
              padding: 8,
              attrs: {
                fill: 'rgba(95,149,255,0.05)',
                stroke: '#5F95FF',
                strokeWidth: 1,
                strokeDasharray: 'none',
              },
            },
          },
          { name: 'button-remove', args: { x: '100%', y: '20%', offset: { x: 0, y: 0 } } },
        ]);
        const ports = (node as Node).getPorts();
        if (ports.length > 0)
          ports.forEach(port => {
            if (port.id)
              (node as Node).setPortProp(port.id, 'attrs/circle/style/visibility', 'visible');
          });
      });
      graph.on('node:mouseleave', ({ node }) => {
        const element = propsRef.current.elements.find(e => e.id === node.id);
        if (element?.type === 'background' || element?.properties?.locked) return;
        (node as Node).removeTools();
        const ports = (node as Node).getPorts();
        if (ports.length > 0)
          ports.forEach(port => {
            if (port.id)
              (node as Node).setPortProp(port.id, 'attrs/circle/style/visibility', 'hidden');
          });
      });
      graph.on('edge:mouseenter', ({ edge }) =>
        edge.addTools([
          'source-arrowhead',
          'target-arrowhead',
          { name: 'button-remove', args: { distance: '48%', offset: { x: 0, y: 0 } } },
        ])
      );
      graph.on('edge:mouseleave', ({ edge }) => edge.removeTools());
      const handleEdgeChange = (edge: Edge) => {
        const edgeData = {
          id: edge.id,
          source: edge.getSource(),
          target: edge.getTarget(),
          vertices: edge.getVertices(),
          router: edge.getRouter(),
          connector: edge.getConnector(),
          attrs: edge.getAttrs(),
        };
        if (propsRef.current.edges?.some(e => e.id === edge.id))
          propsRef.current.onUpdateElement?.(edge.id, edgeData);
      };
      graph.on('edge:change:source', ({ edge }) => handleEdgeChange(edge));
      graph.on('edge:change:target', ({ edge }) => handleEdgeChange(edge));
      graph.on('edge:change:vertices', ({ edge }) => handleEdgeChange(edge));
      graph.on('edge:change:attrs', ({ edge }) => handleEdgeChange(edge));
      graph.on('edge:change:router', ({ edge }) => handleEdgeChange(edge));
      graph.on('edge:change:connector', ({ edge }) => handleEdgeChange(edge));
      graph.bindKey(['meta+c', 'ctrl+c'], () => {
        const cells = graph.getSelectedCells();
        if (cells.length) {
          // 检查是否只选中了边
          const onlyEdges = cells.every(cell => cell.isEdge());

          if (onlyEdges) {
            // 如果只选中边，使用自定义复制逻辑，避免复制连接的节点
            const edgeData = cells.map(cell => {
              const edge = propsRef.current.edges?.find(e => e.id === cell.id);
              return {
                cellData: {
                  id: cell.id,
                  source: cell.getSource(),
                  target: cell.getTarget(),
                  vertices: cell.getVertices(),
                  router: cell.getRouter(),
                  connector: cell.getConnector(),
                  attrs: cell.getAttrs(),
                  zIndex: cell.getZIndex() || 1000,
                },
                originalEdge: edge,
              };
            });

            // 将边数据存储到一个临时的全局变量中
            (window as any).__edgeClipboard = edgeData;
            (window as any).__isEdgeOnlyClipboard = true;
          } else {
            // 正常的复制逻辑（包含节点）
            cells.forEach(cell => {
              if (cell.isNode()) {
                const element = propsRef.current.elements.find(e => e.id === cell.id);
                if (element) {
                  cell.setData({
                    originalElement: element,
                  });
                }
              } else if (cell.isEdge()) {
                const edge = propsRef.current.edges?.find(e => e.id === cell.id);
                if (edge) {
                  cell.setData({
                    originalEdge: edge,
                  });
                }
              }
            });
            graph.copy(cells);
            (window as any).__isEdgeOnlyClipboard = false;
          }
        }
        return false;
      });
      graph.bindKey(['meta+x', 'ctrl+x'], () => {
        const cells = graph.getSelectedCells();
        if (cells.length) graph.cut(cells);
        return false;
      });
      graph.bindKey(['meta+v', 'ctrl+v'], () => {
        // 检查是否是只复制边的情况
        if ((window as any).__isEdgeOnlyClipboard && (window as any).__edgeClipboard) {
          const edgeData = (window as any).__edgeClipboard;
          const pastedCells: any[] = [];

          edgeData.forEach((data: any) => {
            const newId = crypto.randomUUID();
            const { cellData, originalEdge } = data;

            // 简单地在原有连接点位置基础上偏移20px
            const offsetPoint = (point: any) => {
              if (point && typeof point.x === 'number' && typeof point.y === 'number') {
                return { x: point.x + 20, y: point.y + 20 };
              }
              return point; // 如果不是坐标格式，保持原样
            };

            // 创建新的边配置，统一使用直线样式
            const newEdgeConfig = {
              ...cellData,
              id: newId,
              source: offsetPoint(cellData.source),
              target: offsetPoint(cellData.target),
              vertices: [], // 清空顶点，使边变成直线
              router: { name: 'normal' }, // 使用直线路由
              connector: { name: 'normal' }, // 使用直线连接器
            };

            // 添加到画布
            const newEdge = graph.addEdge(newEdgeConfig);
            pastedCells.push(newEdge);

            // 添加到 React 状态
            const newEdgeData = originalEdge
              ? {
                ...originalEdge,
                id: newId,
                source: newEdgeConfig.source,
                target: newEdgeConfig.target,
                vertices: newEdgeConfig.vertices,
              }
              : newEdgeConfig;

            propsRef.current.onAddEdge?.(newEdgeData);
          });

          // 选中新粘贴的边
          graph.cleanSelection();
          graph.select(pastedCells);
        } else if (!graph.isClipboardEmpty()) {
          // 正常的粘贴逻辑
          const cells = graph.paste({ offset: 20 });
          graph.cleanSelection();
          graph.select(cells);

          // 同步粘贴的元素到 React 状态
          cells.forEach(cell => {
            if (cell.isNode()) {
              // 处理节点
              const originalElement = cell.getData()?.originalElement;
              if (originalElement) {
                // 使用原始元素数据，但更新位置和ID
                const newElement = {
                  ...originalElement,
                  id: cell.id,
                  position: cell.getPosition(),
                  properties: {
                    ...originalElement.properties,
                    name: `${originalElement.properties.name || '未命名'} (副本)`,
                  },
                };
                propsRef.current.onAddElement(newElement);
              } else {
                // 如果没有原始数据，创建基本节点数据
                const nodeData = {
                  id: cell.id,
                  type: 'device',
                  position: cell.getPosition(),
                  size: cell.getSize(),
                  angle: cell.getAngle() || 0,
                  zIndex: cell.getZIndex() || 100,
                  properties: {
                    name: `复制的节点-${cell.id.substring(0, 8)}`,
                  },
                };
                propsRef.current.onAddElement(nodeData);
              }
            } else if (cell.isEdge()) {
              // 处理边
              const originalEdge = cell.getData()?.originalEdge;
              if (originalEdge) {
                // 使用原始边数据，但更新ID和连接点
                const newEdge = {
                  ...originalEdge,
                  id: cell.id,
                  source: cell.getSource(),
                  target: cell.getTarget(),
                  vertices: cell.getVertices(),
                };
                propsRef.current.onAddEdge?.(newEdge);
              } else {
                // 如果没有原始数据，创建基本边数据
                const edgeData = {
                  id: cell.id,
                  source: cell.getSource(),
                  target: cell.getTarget(),
                  vertices: cell.getVertices(),
                  router: cell.getRouter(),
                  connector: cell.getConnector(),
                  attrs: cell.getAttrs(),
                  zIndex: cell.getZIndex() || 1000,
                };
                propsRef.current.onAddEdge?.(edgeData);
              }
            }
          });
        }
        return false;
      });
      graph.bindKey(['meta+z', 'ctrl+z'], () => {
        if (graph.canUndo()) graph.undo();
        return false;
      });
      graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
        if (graph.canRedo()) graph.redo();
        return false;
      });
      graph.bindKey(['backspace', 'delete'], () => {
        const cells = graph.getSelectedCells();
        if (cells.length) graph.removeCells(cells);
        return false;
      });

      // 批量选中元素键盘移动功能
      // 通用移动函数
      const moveSelectedCells = (deltaX: number, deltaY: number) => {
        const selectedCells = graph.getSelectedCells();
        if (selectedCells.length > 0) {
          selectedCells.forEach(cell => {
            if (cell.isNode()) {
              // 处理节点移动
              const position = cell.getPosition();
              const newPosition = { x: position.x + deltaX, y: position.y + deltaY };
              cell.setPosition(newPosition.x, newPosition.y);
              // 同步更新 React 状态
              propsRef.current.onUpdateElement(cell.id, { position: newPosition });
            } else if (cell.isEdge()) {
              // 处理边移动（通过移动顶点）
              const vertices = cell.getVertices();
              if (vertices && vertices.length > 0) {
                const newVertices = vertices.map(vertex => ({
                  x: vertex.x + deltaX,
                  y: vertex.y + deltaY,
                }));
                cell.setVertices(newVertices);
                // 同步更新 React 状态
                const edgeData = {
                  id: cell.id,
                  source: cell.getSource(),
                  target: cell.getTarget(),
                  vertices: newVertices,
                  router: cell.getRouter(),
                  connector: cell.getConnector(),
                  attrs: cell.getAttrs(),
                };
                propsRef.current.onUpdateElement(cell.id, edgeData);
              }
            }
          });
        }
        return false;
      };

      // Shift + 方向键：批量移动10px
      graph.bindKey(['shift+up'], () => moveSelectedCells(0, -10));
      graph.bindKey(['shift+down'], () => moveSelectedCells(0, 10));
      graph.bindKey(['shift+left'], () => moveSelectedCells(-10, 0));
      graph.bindKey(['shift+right'], () => moveSelectedCells(10, 0));

      // 单独方向键：批量移动1px
      graph.bindKey(['up'], () => moveSelectedCells(0, -1));
      graph.bindKey(['down'], () => moveSelectedCells(0, 1));
      graph.bindKey(['left'], () => moveSelectedCells(-1, 0));
      graph.bindKey(['right'], () => moveSelectedCells(1, 0));

      if (!listenersAddedRef.current && containerRef.current) {
        containerRef.current.addEventListener('dragover', handleDragOver);
        containerRef.current.addEventListener('drop', handleDrop);
        listenersAddedRef.current = true;
      }
    } else {
      // read-only mode click listener
      graph.on('node:click', ({ node }) => {
        const element = propsRef.current.elements.find(e => e.id === node.id);
        if (element) {
          propsRef.current.onSelectElement(element);
        }
      });
    }

    const resizeObserver = new ResizeObserver(() =>
      graph.resize(containerRef.current!.clientWidth, containerRef.current!.clientHeight)
    );
    resizeObserver.observe(containerRef.current!);

    return () => {
      if (!readOnly && containerRef.current && listenersAddedRef.current) {
        containerRef.current.removeEventListener('dragover', handleDragOver);
        containerRef.current.removeEventListener('drop', handleDrop);
        listenersAddedRef.current = false;
      }
      graph.dispose();
      resizeObserver.disconnect();
    };
  }, [readOnly]);

  // ==================== 同步 React 状态到 X6 画布 ====================
  useEffect(() => {
    if (!graphRef.current) return;
    const graph = graphRef.current;

    const buildAttrs = (element: CanvasElement) => {
      const { properties, type } = element;
      const attrs: Record<string, any> = {};

      // Step 1: Set body and icon attrs based on type
      if (type === 'background' || type === 'image') {
        attrs.body = {
          refWidth: '100%',
          refHeight: '100%',
          fill: properties.backgroundColor || '#ffffff',
          stroke: properties.borderEnabled ? properties.borderColor || '#d9d9d9' : 'transparent',
          strokeWidth: properties.borderEnabled ? (properties.borderWidth ?? 1) : 0,
          rx: 4,
          ry: 4,
        };
        if (properties.borderStyle === 'dashed') attrs.body.strokeDasharray = '5 5';
        else if (properties.borderStyle === 'dotted') attrs.body.strokeDasharray = '1 5';
        else attrs.body.strokeDasharray = 'none';

        const positionMap: { [key: string]: string } = {
          center: 'xMidYMid',
          'left top': 'xMinYMin',
          'left center': 'xMinYMid',
          'left bottom': 'xMinYMax',
          'right top': 'xMaxYMin',
          'right center': 'xMaxYMid',
          'right bottom': 'xMaxYMax',
          'center top': 'xMidYMin',
          'center bottom': 'xMidYMax',
        };
        const fitMap: { [key: string]: string } = { contain: 'meet', cover: 'slice' };
        const backgroundFit = properties.backgroundFit || 'cover';
        const backgroundPosition = properties.backgroundPosition || 'center';
        let preserveAspectRatio = 'xMidYMid slice';
        if (backgroundFit === 'fill') {
          preserveAspectRatio = 'none';
        } else {
          const align = positionMap[backgroundPosition] || 'xMidYMid';
          const meetOrSlice = fitMap[backgroundFit] || 'meet';
          preserveAspectRatio = `${align} ${meetOrSlice}`;
        }

        const borderWidth = properties.borderEnabled === false ? 0 : (properties.borderWidth ?? 1);
        attrs.icon = {
          'xlink:href': properties.imageUrl || '',
          visibility: properties.imageUrl ? 'visible' : 'hidden',
          preserveAspectRatio,
          x: borderWidth,
          y: borderWidth,
          refWidth: '100%',
          width: -(borderWidth * 2),
          refHeight: '100%',
          height: -(borderWidth * 2),
        };
      } else {
        const getIconUrl = (iconName?: string) => {
          if (!iconName) return '';
          return new URL(`../../../../assets/icon/${iconName}.svg`, import.meta.url).href;
        };
        const hasIcon = !!properties.icon;
        const iconUrl = getIconUrl(properties.icon);

        attrs.body = {
          fill: properties.backgroundEnabled ? properties.backgroundColor || '#fff' : 'transparent',
          stroke: properties.borderEnabled ? properties.borderColor || '#5F95FF' : 'transparent',
          strokeWidth: properties.borderEnabled ? (properties.borderWidth ?? 1) : 0,
          rx: 4,
          ry: 4,
        };
        if (properties.borderStyle === 'dashed') attrs.body.strokeDasharray = '5 5';
        else if (properties.borderStyle === 'dotted') attrs.body.strokeDasharray = '1 5';
        else attrs.body.strokeDasharray = 'none';

        if (hasIcon) {
          const borderWidth =
            properties.borderEnabled === false ? 0 : (properties.borderWidth ?? 1);
          attrs.icon = {
            'xlink:href': iconUrl,
            x: borderWidth,
            y: borderWidth,
            refWidth: '100%',
            width: -(borderWidth * 2),
            refHeight: '100%',
            height: -(borderWidth * 2),
            visibility: 'visible',
          };
        } else {
          attrs.icon = { visibility: 'hidden' };
        }
      }

      // Step 2: Set label attrs
      if (type === 'background') {
        attrs.label = { text: '', visibility: 'hidden' };
      } else {
        const vSpan = properties.labelVSpan ?? 10;
        const hSpan = properties.labelHSpan ?? 0;
        const labelPosition = properties.labelPosition || 'bottom';

        // 对于文本组件，使用textContent作为显示内容
        const displayText = type === 'text' ? properties.textContent || '' : properties.name || '';

        attrs.label = {
          text: displayText,
          visibility: properties.labelEnabled === false ? 'hidden' : 'visible',
          fill: properties.labelColor || '#333',
          fontSize: properties.labelFontSize || 12,
          fontWeight: properties.labelFontWeight || 'normal',
          // 添加换行支持
          wordWrap: type === 'text' ? properties.labelWrap === 'normal' : false,
          // 如果是文本组件且启用了换行，设置宽度
          ...(type === 'text' && properties.labelWrap === 'normal'
            ? { width: element.size.width || 100 }
            : {}),
        };

        switch (labelPosition) {
          case 'top':
            attrs.label.refX = '50%';
            attrs.label.refY = 0;
            attrs.label.refX2 = hSpan;
            attrs.label.refY2 = -vSpan;
            attrs.label.textAnchor = 'middle';
            break;
          case 'left-center':
            attrs.label.refX = 0;
            attrs.label.refX2 = -hSpan;
            attrs.label.refY = '50%';
            attrs.label.textAnchor = 'end';
            break;
          case 'right-center':
            attrs.label.refX = '100%';
            attrs.label.refX2 = hSpan;
            attrs.label.refY = '50%';
            attrs.label.textAnchor = 'start';
            break;
          case 'center':
            attrs.label.refX = '50%';
            attrs.label.refY = '50%';
            attrs.label.refX2 = hSpan;
            attrs.label.textAnchor = 'middle';
            break;
          case 'top-left':
            attrs.label.refX = 0;
            attrs.label.refY = 0;
            attrs.label.refX2 = -hSpan;
            attrs.label.refY2 = -vSpan;
            attrs.label.textAnchor = 'end';
            break;
          case 'top-right':
            attrs.label.refX = '100%';
            attrs.label.refY = 0;
            attrs.label.refX2 = hSpan;
            attrs.label.refY2 = -vSpan;
            attrs.label.textAnchor = 'start';
            break;
          case 'bottom-left':
            attrs.label.refX = 0;
            attrs.label.refY = '100%';
            attrs.label.refX2 = -hSpan;
            attrs.label.refY2 = vSpan;
            attrs.label.textAnchor = 'end';
            break;
          case 'bottom-right':
            attrs.label.refX = '100%';
            attrs.label.refY = '100%';
            attrs.label.refX2 = hSpan;
            attrs.label.refY2 = vSpan;
            attrs.label.textAnchor = 'start';
            break;
          default:
            attrs.label.refX = '50%';
            attrs.label.refY = '100%';
            attrs.label.refX2 = hSpan;
            attrs.label.refY2 = vSpan;
            attrs.label.textAnchor = 'middle';
            break;
        }
      }

      return attrs;
    };

    const nodesOnGraph = graph.getNodes();
    const nodeIdsOnGraph = new Set(nodesOnGraph.map(n => n.id));
    const elementIdsInState = new Set(elements.map(e => e.id));

    nodeIdsOnGraph.forEach(id => {
      if (!elementIdsInState.has(id)) graph.removeNode(id);
    });

    elements.forEach(element => {
      const existingNode = graph.getCellById(element.id) as Node;
      const newAttrs = buildAttrs(element);

      if (existingNode) {
        if (
          element.position.x !== existingNode.getPosition().x ||
          element.position.y !== existingNode.getPosition().y
        )
          existingNode.setPosition(element.position);
        if (
          element.size.width !== existingNode.getSize().width ||
          element.size.height !== existingNode.getSize().height
        )
          existingNode.setSize(element.size);
        if ((element.angle || 0) !== existingNode.getAngle())
          existingNode.rotate(element.angle || 0, { absolute: true });
        if ((element.zIndex || 0) !== existingNode.getZIndex())
          existingNode.setZIndex(element.zIndex || 0);
        existingNode.setAttrs(newAttrs);
        if (element.type === 'background') existingNode.toBack();
      } else {
        const portOffset = 12;
        const portAttrs = {
          circle: {
            r: 4,
            magnet: true,
            stroke: '#5F95FF',
            strokeWidth: 1,
            fill: '#fff',
            style: { visibility: 'hidden' },
          },
        };
        const nodeConfig: Node.Metadata = {
          id: element.id,
          shape: 'custom-element',
          x: element.position.x,
          y: element.position.y,
          width: element.size.width,
          height: element.size.height,
          angle: element.angle,
          zIndex: element.zIndex,
          attrs: newAttrs,
        };
        if (element.type !== 'background') {
          nodeConfig.ports = {
            groups: {
              top: {
                position: { name: 'absolute', args: { x: '50%', y: 0, dy: portOffset } },
                attrs: portAttrs,
              },
              bottom: {
                position: { name: 'absolute', args: { x: '50%', y: '100%', dy: -portOffset } },
                attrs: portAttrs,
              },
              left: {
                position: { name: 'absolute', args: { x: 0, y: '50%', dx: portOffset } },
                attrs: portAttrs,
              },
              right: {
                position: { name: 'absolute', args: { x: '100%', y: '50%', dx: -portOffset } },
                attrs: portAttrs,
              },
              topLeft: {
                position: {
                  name: 'absolute',
                  args: { x: 0, y: 0, dx: portOffset, dy: portOffset },
                },
                attrs: portAttrs,
              },
              topRight: {
                position: {
                  name: 'absolute',
                  args: { x: '100%', y: 0, dx: -portOffset, dy: portOffset },
                },
                attrs: portAttrs,
              },
              bottomLeft: {
                position: {
                  name: 'absolute',
                  args: { x: 0, y: '100%', dx: portOffset, dy: -portOffset },
                },
                attrs: portAttrs,
              },
              bottomRight: {
                position: {
                  name: 'absolute',
                  args: { x: '100%', y: '100%', dx: -portOffset, dy: -portOffset },
                },
                attrs: portAttrs,
              },
            },
            items: [
              { group: 'top' },
              { group: 'bottom' },
              { group: 'left' },
              { group: 'right' },
              { group: 'topLeft' },
              { group: 'topRight' },
              { group: 'bottomLeft' },
              { group: 'bottomRight' },
            ],
          };
        }
        const newNode = graph.addNode(nodeConfig);
        if (element.type === 'background') newNode.toBack();

        // 如果是背景类型或被锁定，则禁用移动和调整大小
        if (element.type === 'background' || element.properties?.locked) {
          // 禁用节点的移动和调整大小
          newNode.setAttrByPath('body/style/pointer-events', 'none');
          // 禁用Transform插件对该节点的作用
          newNode.removeTools();
        }
      }
    });

    if (selectOnAddRef.current && graph.getCellById(selectOnAddRef.current)) {
      graph.cleanSelection();
      graph.select(selectOnAddRef.current);
      propsRef.current.onSelectElement(elements.find(e => e.id === selectOnAddRef.current) || null);
      selectOnAddRef.current = null;
    }
  }, [elements]);

  useEffect(() => {
    if (!graphRef.current) return;
    const graph = graphRef.current;
    const edgesOnGraph = graph.getEdges();
    const edgeIdsOnGraph = new Set(edgesOnGraph.map(e => e.id));
    const edgeIdsInState = new Set(edges.map(e => e.id));

    edgeIdsOnGraph.forEach(id => {
      if (!edgeIdsInState.has(id)) graph.removeEdge(id);
    });

    edges.forEach(edgeData => {
      const existingEdge = graph.getCellById(edgeData.id) as Edge;
      if (existingEdge) {
        if (JSON.stringify(existingEdge.getAttrs()) !== JSON.stringify(edgeData.attrs))
          existingEdge.setAttrs(edgeData.attrs);
        const currentVertices = existingEdge.getVertices() || [];
        const newVertices = edgeData.vertices || [];
        if (JSON.stringify(currentVertices) !== JSON.stringify(newVertices))
          existingEdge.setVertices(newVertices);
        // 处理router更新
        if (JSON.stringify(existingEdge.getRouter()) !== JSON.stringify(edgeData.router))
          existingEdge.setRouter(edgeData.router);
        // 处理connector更新
        if (JSON.stringify(existingEdge.getConnector()) !== JSON.stringify(edgeData.connector))
          existingEdge.setConnector(edgeData.connector);
        if ((edgeData.zIndex ?? 1000) !== existingEdge.getZIndex())
          existingEdge.setZIndex(edgeData.zIndex ?? 1000);
      } else {
        const edgeConfig = {
          ...edgeData,
          zIndex: edgeData.zIndex || 1000,
          attrs: {
            ...edgeData.attrs,
            line: {
              ...edgeData.attrs?.line,
              style: { cursor: 'pointer', ...edgeData.attrs?.line?.style },
            },
          },
        };
        graph.addEdge(edgeConfig);
      }
    });
  }, [edges]);

  // 注释：缩放现在由外层视口容器处理，X6内部保持1:1比例
  // useEffect(() => {
  //   if (graphRef.current) {
  //     graphRef.current.zoomTo(scale);
  //   }
  // }, [scale]);

  // Grid
  useEffect(() => {
    if (graphRef.current && props.gridOptions) {
      if (props.gridOptions.visible) {
        graphRef.current.drawGrid(props.gridOptions);
      } else {
        graphRef.current.clearGrid();
      }
    }
  }, [props.gridOptions]);

  // Background
  useEffect(() => {
    if (graphRef.current && props.backgroundOptions) {
      if (props.backgroundOptions.visible) {
        graphRef.current.drawBackground(props.backgroundOptions);
      } else {
        graphRef.current.clearBackground();
      }
    }
  }, [props.backgroundOptions]);

  // 监听画布尺寸变化
  useEffect(() => {
    if (graphRef.current && canvasSize) {
      graphRef.current.resize(canvasSize.width, canvasSize.height);
    }
  }, [canvasSize]);

  return (
    <div className="h-full w-full">
      <div ref={containerRef} className="h-full w-full" />
    </div>
  );
};

export default X6Canvas;
